/************************************************************
  基本思路：修改聊天室项目，通过判断客户端传来的消息执行对应命令（如传来"ls",则执行lsFunction函数）
  函数目录：（在此处写函数名和函数功能简述和返回值）

  char* substring(char* str, int start, int end); // 截取文件名（如：rm filename则返回char*类型的filename）  -莫开林

  void lsFunction(int clientfd);                  // ls功能实现   -莫开林

  void mkdirFunction(int clientfd,char* buf);     // mkdir功能实现  -陈扬

  void rmFunction(int clientfd, char *buf);       // rm功能实现   -莫开林

  void pwdFuction(int clientfd);                  //pwd功能  -郭子卿

  void unknowFunction();                          // 未知命令功能   -莫开林

  int sendBroadcastmessage(int clientfd);         // 将一期功能添加到此函数if-else判断里

 ************************************************************/


#include "func.h"
#include "function.h"
#include "mysql.h"

extern int exitPipe[2];

void sigFunc(int signum)                                                                        
{                                                                                               
    printf("signum = %d\n", signum);                                                            
    write(exitPipe[1], "1", 1);                                                                 
    puts("Parent exit!");                                                                       
}                                                                                               
                                                                                                
char* substring(char* str, int start, int end)                                                  
{                                                                                               
    int i = 0;                                                                                  
    char* sub = NULL;                                                                           
    char buff[1024];                                                                            
    if(start < 0 || start >= end || (int)strlen(str) < end)                                          
        return str;                                                                             
    for(i = start; i < end; i++)                                                                
        buff[i - start] = str[i];                                                               
    buff[end - start] = '\0';                                                                   
    sub = buff;                                                                                 
    return sub;                                                                                 
}                                                                                               
                                                                                                
void lsFunction(int clientfd, MYSQL * conn, char * username)                                    
{                                                                                               
    char message[255];                                                                          
    const char * temp = "\'";                                                                         
    char query1[64] = "select id from User where username = '";                                 
    strcat(query1, username);                                                                   
    strcat(query1, temp);                                                                       
    mysql_query(conn, query1);                                                                  
    MYSQL_RES * idRes = mysql_store_result(conn);                                               
    MYSQL_ROW idRow = mysql_fetch_row(idRes);                                                   
                                                                                                
    char query2[64] = "select filename from File where owner_id = '";                           
    strcat(query2, idRow[0]);                                                                   
    strcat(query2, temp);                                                                       
    mysql_query(conn, query2);                                                                  
    MYSQL_RES * queryRes = mysql_store_result(conn);                                            
    MYSQL_ROW queryRow;                                                                         
    int cols = mysql_num_fields(queryRes);                                                      
    while((queryRow = mysql_fetch_row(queryRes)) != NULL)                                       
    {                                                                                           
        for(int i = 0; i < cols; ++i)                                                           
        {                                                                                       
            sprintf(message, "%s ", queryRow[i]);                                               
            send(clientfd, message, 64, 0);                                                     
        }                                                                                       
    }                                                                                           
    mysql_free_result(idRes);                                                                   
    mysql_free_result(queryRes);                                                                
}                                                                                               
                                                                                                
void pwdFunction(int clientfd)                                                                   
{                                                                                               
    char buf[1024]={0};                                                                         
    printf("%s\n",getcwd(buf,sizeof(buf)));//服务器上打印路径                                   
    send(clientfd,buf,strlen(buf),0);//发送到客户端                                             
                                                                                                
}                                                                                               

void putsFunction(int clientfd,char *filename,int epollfd){
    //撤掉clientfd监听
    struct epoll_event events;
    events.data.fd = clientfd;
    events.events = EPOLLOUT;
    epoll_ctl(epollfd,EPOLL_CTL_MOD,clientfd,&events);
    send(clientfd,"server is already putsfunc",27,0);
    int ret;
    off_t filexistmark = 0; //用于记录文件当前位置，及偏移量
    int filefd = open(filename,O_RDWR);
    if(-1 == filefd){
        //说明没有该文件
        filefd = open(filename,O_RDWR | O_CREAT | O_TRUNC, 0666);
        filexistmark = 0;
    }else{
        //说明该文件已经存在
        struct stat file_stat;
        fstat(filefd,&file_stat);
        filexistmark = file_stat.st_size;
    }

    //接受文件总大小
    int filesizeoflength = 0;
    long filesize = 0;
    ret = recv(clientfd,&filesizeoflength,4,MSG_WAITALL);
    printf("filesizeoflength:%d\n",filesizeoflength);
    ret = recv(clientfd,&filesize,filesizeoflength,MSG_WAITALL);
    printf(">>filesize length:%ld<<\n",filesize);

    //发送偏移量
    ret = send(clientfd,&filexistmark,8,0);
    printf("send %d charactor\n",ret);
    printf("send file offset:%ld\n",filexistmark);

    //判断大文件小文件
    if(filesize - filexistmark < (long)100* 1024){
        printf("small file\n");
        lseek(filefd,SEEK_SET,filexistmark);
        putsFunction_smallfile(clientfd,filefd,filesize - filexistmark);
    }else{
        printf("big file\n");
        ftruncate(filefd,filesize);
        putsFunction_bigfile(clientfd,filefd,filesize,filexistmark);
    }

    //撤掉clientfd监听
    events.data.fd = clientfd;
    events.events = EPOLLIN;
    epoll_ctl(epollfd,EPOLL_CTL_MOD,clientfd,&events);
}
void putsFunction_bigfile(int clientfd,int filefd,off_t filesize,off_t filexistmark)
{
    printf("clientfd:%d,filefd:%d,filesize:%ld,filexistmark:%ld\n",clientfd,filefd,filesize,filexistmark);
    //接受文件
    char * pbuf = (char *) mmap(NULL,filesize,PROT_READ | PROT_WRITE, MAP_SHARED, filefd, 0);
    int ret = recv(clientfd,pbuf+filexistmark,filesize - filexistmark,MSG_WAITALL);
    printf("putsfunction_bigfile:recvn:%d\n",ret);
    printf("recv big file over\n");
    close(filefd);
    munmap(pbuf,filexistmark );

}


void putsFunction_smallfile(int clientfd,int filefd,off_t filesize){
    printf("clientfd:%d,filefd:%d,filesize:%ld\n",clientfd,
                filefd,filesize);
    int retval;
    off_t slice = filesize/100;
    off_t downloadsize=0;
    off_t lastsize = 0;
    char buf[1024] = {0};
    while(downloadsize<filesize){
        memset(buf,0,sizeof(buf));
        retval = recv(clientfd,buf,sizeof(buf),0);
        downloadsize+=retval;
        if(downloadsize - lastsize>slice){
            printf(">> download percent:%5.2lf%%\n",(double)downloadsize/filesize*100);
            lastsize = downloadsize;
        }
        retval = write(filefd,buf,retval);
        ERROR_CHECK(retval,-1,"write");
    }
    printf(">>download percent:100%%\n");
    printf("putsfunc is over!\n");
    close(filefd);
}


int sendn(int fd, const void * buf, int len)                                  
{
    int left = len;
    char * pbuf = (char *)buf;
    int ret;
    while(left > 0) {
        ret = send(fd, pbuf, left, 0);
        if(ret < 0) {
            perror("send");
            break;
        } else {
            pbuf += ret;
            left -= ret;
        }
    }
    return len - left;
}

void getsFunction(int clientfd, char * filename,int epollfd){
    //撤掉clientfd监听
    struct epoll_event events;
    events.data.fd = clientfd;
    events.events = EPOLLOUT;
    epoll_ctl(epollfd,EPOLL_CTL_MOD,clientfd,&events);
    int ret;
    train_t train;

    int filefd = open(filename, O_RDWR);
    ERROR_CHECK(filefd,-1,"open file");
    //发送长度
    memset(&train,0,sizeof(train));
    struct stat file_stat;
    fstat(filefd,&file_stat);
    off_t filesize = file_stat.st_size;
    train.length = sizeof(off_t);
    strncpy(train.data,(char*)&filesize,train.length);
    ret = sendn(clientfd,&train,4 + train.length);
    printf("file length:%ld\n",file_stat.st_size);

    //接受文件偏移量
    off_t filexistmark = 0;
    ret = recv(clientfd,&filexistmark,8,0);
    printf("recv file offset:%ld\n",filexistmark);
    //传文件选择
    if(filesize-filexistmark < (long)100*1024){
        printf("small file\n");
        lseek(filefd,SEEK_SET,filexistmark);
        getsFunction_smallfile(clientfd,filefd,filesize - filexistmark);
    }else{
        printf("big file\n");
        getsFunction_bigfile(clientfd,filefd,filesize,filexistmark);
    }

    //添加回clientfd监听
    events.data.fd = clientfd;
    events.events = EPOLLIN;
    epoll_ctl(epollfd,EPOLL_CTL_MOD,clientfd,&events);
}

void getsFunction_bigfile(int clientfd,int filefd,off_t filesize,off_t filexistmark)
{
    int ret = 0;
    //发送文件内容
    char * pbuf = (char *)mmap(NULL,
            filesize,PROT_READ | PROT_WRITE,MAP_SHARED, filefd, 0);
    ret = send(clientfd,pbuf+filexistmark,filesize-filexistmark,MSG_WAITALL);
    printf("sendn:%d charactor\n",ret);
    perror("big file send");
    printf("big file send over!\n");
    close(filefd);
    munmap(pbuf, filesize);

}

void getsFunction_smallfile(int clientfd, int filefd, off_t filesize){
    printf("clientfd:%d,filefd:%d,filesize:%ld\n",clientfd,
           filefd,filesize);
    train_t train;
    memset(&train,0,sizeof(train));
    printf("begin!\n");
    char buf[1024]={0};
    memset(buf,0,sizeof(buf));
    off_t sendsize = 0;
    while(sendsize<filesize){
        int retval = read(filefd,buf,sizeof(buf));
        retval = send(clientfd,buf,retval,0);
        printf("send:%s\n",buf);
        sendsize+=retval;
        memset(buf,0,sizeof(buf));
    }
    close(filefd);
    printf("file send over!\n");
}
                                                                                           
void rmFunction(int clientfd, char *buf, MYSQL * conn)                                       
{                                                                                            
    char message[64];                                                                        
    char * temp = "\'";                                                                      
    int i = 3;                                                                               
    for(; i < strlen(buf); i++)                                                              
        if(buf[i] == '\0')                                                                   
            break;                                                                           
    char * filename = substring(buf, 3, i);                                                  
    char query[64] = "delete from File where filename = '";                                  
    strcat(query, filename);                                                                 
    strcat(query, temp);                                                                     
    mysql_query(conn, query);                                                                
    int ret = unlink(filename);                                                              
    ERROR_CHECK(ret, -1, "unlink");                                                          
    sprintf(message, "rm success\n");                                                        
    send(clientfd, message, 64, 0);                                                          
}                                                                                            
                                                                                             
void mkdirFunction(int clientfd,MYSQL* conn,char* username,char* buf)                                                   
{                                                                                            
    //./mkdir dir
    int i=6;                                                                                 
    for(;i<strlen(buf);++i)                                                                  
    {                                                                                        
        if(buf[i]=='\0')                                                                     
            break;                                                                           
    }                                                                                        
    char* buff=substring(buf,6,i);
    char* filename=buff;
    char parent_id[100]={0};
    getcwd(parent_id,sizeof(parent_id));
    InsertFile(conn,parent_id,filename,0,NULL,0,0);
    int retval=mkdir(buff,0664);                                                             
    ERROR_CHECK(retval,-1,"mkdir"); 

    printf("do mkdirFunciont.\n");                                                           
}                                                                                            
                                                                                             
void cdFunction(int clientfd){                                                               
    char pathname[50] = {0};                                                                 
    sprintf(pathname,"%d",clientfd);                                                         
    for(int i =0;pathname[i]!='\0';++i){                                                     
    if(' ' == pathname[i]){                                                                  
    pathname[i] = '\0';                                                                      
    break;                                                                                   
   }                                                                                         
}                                                                                            
    int ret = chdir(pathname);                                                               
    if(-1 == ret){                                                                           
    printf("do cdFunciont.\n");                                                              
}                                                                                            
}                                                                                            
                                                                                           

 int sysNote(char * buf)
 {
         time_t now = time(NULL);
         struct tm *pTm = localtime(&now);
         syslog(LOG_INFO,"%4d%2d%2d %2d:%2d:%2d user输入的内容为:%s\n",
                 pTm->tm_year+1900,pTm->tm_mon+1, pTm->tm_mday,
                 pTm->tm_hour, pTm->tm_min, pTm->tm_sec,
                 buf);
 }   

#undef USER
